﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace LowLevelGraphics.Filter
{

//exaggerated emboss
//double filter[filterWidth][filterHeight] =
//{
//    -1, -1, -1, -1,  0,
//    -1, -1, -1,  0,  1,
//    -1, -1,  0,  1,  1,
//    -1,  0,  1,  1,  1,
//     0,  1,  1,  1,  1
//};

//double factor = 1.0;
//double bias = 128.0;
 //==========================================)

//subtle sharpen
//double filter[filterWidth][filterHeight] =
//{
//    -1, -1, -1, -1, -1,
//    -1,  2,  2,  2, -1,
//    -1,  2,  8,  2, -1,
//    -1,  2,  2,  2, -1,
//    -1, -1, -1, -1, -1,
//};

//double factor = 1.0 / 8.0;
//double bias = 0.0;

//============================================
//
//    //motionblur
//    double filter[filterWidth,filterHeight] =
//{
//    1, 0, 0, 0, 0, 0, 0, 0, 0,
//    0, 1, 0, 0, 0, 0, 0, 0, 0,
//    0, 0, 1, 0, 0, 0, 0, 0, 0,
//    0, 0, 0, 1, 0, 0, 0, 0, 0,
//    0, 0, 0, 0, 1, 0, 0, 0, 0,
//    0, 0, 0, 0, 0, 1, 0, 0, 0,
//    0, 0, 0, 0, 0, 0, 1, 0, 0,
//    0, 0, 0, 0, 0, 0, 0, 1, 0,
//    0, 0, 0, 0, 0, 0, 0, 0, 1,
//};

//double factor = 1.0 / 9.0;
//double bias = 0.0;

    /// <summary>
    /// 
    /// </summary>
    public class ConvolutionCustom : BaseImageFilter
    {
        protected const int m_cnFilterWidth = 3;
        protected const int m_ncFilterHeight = 3;
        
        protected double[,] m_adFilter = new double[m_cnFilterWidth, m_ncFilterHeight]
        { 
             {0, 0, 0}, 
             {0, 1, 0},
             {0, 0, 0} 
        }; 
       

        protected double m_dFactor = 1.0; 
        protected double m_dBias = 0.0;

        /// <summary>
        /// Initializes a new instance of the <see cref="ConvolutionCustom"/> class.
        /// </summary>
        public ConvolutionCustom()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ConvolutionCustom"/> class.
        /// </summary>
        /// <param name="_convolutionCustom">The _convolution custom.</param>
        internal ConvolutionCustom(ConvolutionCustom _convolutionCustom)
        {
            m_dFactor = _convolutionCustom.m_dFactor;
            m_dBias = _convolutionCustom.m_dBias;
            m_adFilter = _convolutionCustom.m_adFilter;
        }

        /// <summary>
        /// Gets or sets the kernel.
        /// </summary>
        /// <value>The kernel.</value>
        public double[,] Kernel
        {
            get { return m_adFilter; }
            set { m_adFilter = value; }
        }

        /// <summary>
        /// Gets or sets the factor.
        /// </summary>
        /// <value>The factor.</value>
        public double Factor
        {
            get { return m_dFactor; }
            set { m_dFactor = value; }
        }

        public double Bias
        {
            get { return m_dBias; }
            set { m_dBias = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            //apply the filter 

            UnsafeBitmap bitmap = _bitmap;
            int w = bitmap.Width;
            int h = bitmap.Height;
            double dRed = 0.0f;
            double dGreen = 0.0f;
            double dBlue = 0.0f;

            Color color = Color.Transparent;

            int imageX = 0;
            int imageY = 0;

            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    dRed = 0.0f;
                    dGreen = 0.0f;
                    dBlue = 0.0;

                    //multiply every value of the filter with corresponding image pixel 
                    for (int filterX = 0; filterX < m_cnFilterWidth; filterX++)
                    {
                        for (int filterY = 0; filterY < m_ncFilterHeight; filterY++)
                        {
                            imageX = (x - m_cnFilterWidth / 2 + filterX + w) % w;
                            imageY = (y - m_ncFilterHeight / 2 + filterY + h) % h;
                            color = bitmap.GetPixel(imageX, imageY);
                            dRed += color.R * m_adFilter[filterX, filterY];
                            dGreen += color.G * m_adFilter[filterX, filterY];
                            dBlue += color.B * m_adFilter[filterX, filterY];
                        }
                    }

                    //truncate values smaller than zero and larger than 255 
                    bitmap.SetPixel(x, y, Color.FromArgb(
                        Math.Min(Math.Max((int)(m_dFactor * dRed + m_dBias), 0), 255),
                        Math.Min(Math.Max((int)(m_dFactor * dGreen + m_dBias), 0), 255),
                        Math.Min(Math.Max((int)(m_dFactor * dBlue + m_dBias), 0), 255)
                        ));
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ConvolutionCustom(this);
        }
    }
}
